/*******************************************************************************
 * Copyright 2007, 2009 InnovaSoft SA http://www.innovasoft.biz/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/

package biz.innovasoft.nodb.index;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import biz.innovasoft.nodb.query.QueryCriteria;
import biz.innovasoft.nodb.util.IndexUtils;

public class RepositoryIndexManager implements Serializable {

	private static final long serialVersionUID = 8826308879906712359L;

	private Map<String, IndexManager> managers = new HashMap<String, IndexManager>();
	
	public RepositoryIndexManager() {
	}
	
	public void addIndexManager(IndexManager manager) {
		managers.put(manager.getName(), manager);
	}
	
	public IndexManager getIndexManager(String name) {
		return managers.get(name);
	}

	public IndexManager getIndexManager(Class<?> clazz) {
		return createIndexAndPath(clazz);
	}
	
	public IndexManager[] getIndexManagers() {
		return (IndexManager[]) managers.values().toArray(new IndexManager[0]);
	}

	public boolean containsIndexForClass(Class<?> clazz) {
		return managers.containsKey(clazz.getCanonicalName());
	}
	
	public void createIndex(Class<?> clazz, String indexPath) {
		createIndex(clazz, indexPath, true);
	}

	public void createIndex(Class<?> clazz, String indexPath, boolean allowNulls) {
		createIndex (clazz, indexPath, DateResolution.DAY, allowNulls);
	}
	
	public void createIndex(Class<?> clazz, String indexPath, DateResolution resolution, boolean allowNulls) {
		IndexManager idx = createIndexAndPath(clazz);
		IndexEntry entry = new IndexEntry(indexPath, resolution, allowNulls);
		idx.addIndexEntry(entry);
		addIndexManager(idx);
	}

	public void createIndex(Class<?> clazz, String[] indexesPath) {
		for (String indexPath : indexesPath) {
			createIndex(clazz, indexPath, true);
		}
	}

	public void removeIndex (Class<?> clazz) {
		IndexManager idx = managers.get(clazz.getCanonicalName());
		List<IndexManager> childs = idx.getChilds();
		for (IndexManager child : childs) {
			child.setParent(null);
		}
		managers.remove(clazz.getCanonicalName());
	}
	
	public void removeIndex (Class<?> clazz, String indexPath) {
		IndexManager idx = managers.get(clazz.getCanonicalName());
		idx.removeIndexEntry (indexPath);
		if (!idx.hasIndexEntries()) {
			removeIndex (clazz);
		}
	}
	
	public IndexManager createIndexAndPath (Class<?> clazz) {
		IndexManager idx = getIndexManager(clazz.getCanonicalName());
		if (idx == null) {
			idx = new IndexManager(clazz);
			Class<?> superCls = clazz.getSuperclass();
			if (superCls.equals(Object.class)) {
				// TODO: reformulate this.
			} else {
				IndexManager parent = createIndexAndPath(superCls);
				idx.setParent(parent);
				parent.addChild(idx);
			}
			addIndexManager(idx);
		}
		return idx;
	}
	
	public boolean canQueryRunWithIndex(QueryCriteria criteria) {
		List<String> criteriaAttrs = IndexUtils
				.getExpressionAttributes(criteria.getExpressions());
		if (criteriaAttrs.size() == 0)
			return false;
		IndexManager imanager = getIndexManager(criteria.getCriteriaClass()
				.getCanonicalName());
		for (String attr : criteriaAttrs) {
			if (!imanager.containsEntry(attr)) {
				return false;
			}
		}
		return true;
	}

}
